import { createContext, useContext, useRef, useState, useEffect } from 'react';
import CanvasKit from 'canvaskit-wasm';
import fontFiles from '../font-list';

// CanvasKit initialization
let canvasKitInstance = null;

const initCanvasKit = async () => {
  if (canvasKitInstance) return canvasKitInstance;
  
  canvasKitInstance = await CanvasKit({
    locateFile: (file) => `/node_modules/canvaskit-wasm/bin/${file}`,
  });
  return canvasKitInstance;
};

const CanvasKitContext = createContext();

export const useCanvasKit = () => {
  const context = useContext(CanvasKitContext);
  if (!context) {
    throw new Error('useCanvasKit must be used within a CanvasKitProvider');
  }
  return context;
};

export const CanvasKitProvider = ({ children }) => {
  const [canvasKitStatus, setCanvasKitStatus] = useState('loading'); // 'loading', 'ready', 'failed'
  const [fontsLoaded, setFontsLoaded] = useState(false);
  const [availableFonts, setAvailableFonts] = useState([]);
  const [fontManager, setFontManager] = useState(null);
  const surfaceRef = useRef(null);
  const typefaceCacheRef = useRef(new Map()); // Cache for typefaces
  const fontFamilyMapRef = useRef(new Map()); // Map family names to typefaces

  const initFontMgr = async (ck) => {
    const fontDataPromises = [];
    const fontMetadata = [];
    const failedFonts = [];

    console.log('🚀 Starting font loading process...');
    console.log(`📁 Attempting to load ${fontFiles.length} font files`);

    // Load all fonts and collect their data
    for (let i = 0; i < fontFiles.length; i++) {
      const fontFile = fontFiles[i];
      try {
        const fontPath = `/src/assets/fonts/${fontFile}`;
        
        const response = await fetch(fontPath);
        if (!response.ok) {
          throw new Error(`HTTP ${response.status}: ${response.statusText}`);
        }
        const fontData = await response.arrayBuffer();
        
        fontDataPromises.push(fontData);
        fontMetadata.push({ fileName: fontFile, size: fontData.byteLength, index: i });
      } catch (e) {
        failedFonts.push({ fileName: fontFile, index: i, error: e.message });
        fontDataPromises.push(null);
        fontMetadata.push({ fileName: fontFile, size: 0, error: e.message, index: i });
      }
    }

    const validFontData = fontDataPromises.filter(data => data !== null);
    const fontManager = ck.FontMgr.FromData(...validFontData);
    
    if (!fontManager) {
      console.error('❌ Failed to create FontManager');
      return;
    }

    await createAndCacheTypefaces(ck, fontManager);
    
    const fontFamilyNames = extractFontFamilyNames();
    setAvailableFonts(fontFamilyNames);
    setFontsLoaded(true);

    return fontManager;
  };

  const createAndCacheTypefaces = async (ck, fontManager) => {
    const typefaceCache = typefaceCacheRef.current;
    const fontFamilyMap = fontFamilyMapRef.current;
    
    // Define weight and slant ranges to test
    const weightRange = [100, 200, 300, 400, 500, 600, 700, 800, 900];
    const slantRange = [0, -1, 1]; // normal, italic, oblique
    
    // Generate all combinations of weight and slant
    const weightStyleCombinations = [];
    for (const weight of weightRange) {
      for (const slant of slantRange) {
        weightStyleCombinations.push({ weight, slant });
      }
    }

    const seenTypefaces = new Set();
    
    // First, get all font families from the FontManager
    const familyCount = fontManager.countFamilies();
    console.log(`📚 Found ${familyCount} font families in FontManager`);
    
    for (let i = 0; i < familyCount; i++) {
      const familyName = fontManager.getFamilyName(i);
      console.log(`🔍 Processing family: "${familyName}"`);
      
      // Store the default typeface for this family
      if (!fontFamilyMap.has(familyName)) {
        const defaultTypeface = fontManager.matchFamilyStyle(familyName, {
          weight: 400,
          width: ck.FontWidth?.Normal || 5,
          slant: 0
        });
        if (defaultTypeface) {
          fontFamilyMap.set(familyName, defaultTypeface);
        }
      }
      
      // Try each weight/style combination for this family
      for (const combo of weightStyleCombinations) {
        try {
          // Create font style object using the correct CanvasKit API
          const fontStyle = {
            weight: combo.weight,
            width: ck.FontWidth?.Normal || 5,
            slant: combo.slant
          };
          
          const typeface = fontManager.matchFamilyStyle(familyName, fontStyle);
          if (!typeface) continue;
          
          // Create a unique identifier for this typeface
          const typefaceId = `${familyName}-${combo.weight}-${fontStyle.width}-${combo.slant}`;
          
          if (!seenTypefaces.has(typefaceId)) {
            seenTypefaces.add(typefaceId);
            
            // Store in typeface cache with combo info
            const cacheKey = `${familyName}-${combo.weight}-${combo.slant === -1 ? 'italic' : combo.slant === 1 ? 'oblique' : 'normal'}`;
            typefaceCache.set(cacheKey, typeface);
          }
        } catch (error) {
          console.warn(`❌ Error processing ${familyName} weight ${combo.weight}, slant ${combo.slant}:`, error);
        }
      }
    }
    return fontManager;
  };

  const extractFontFamilyNames = () => {
    const fontFamilyMap = fontFamilyMapRef.current;
    const familyNames = Array.from(fontFamilyMap.keys()).sort();
    console.log(`📝 Extracted ${familyNames.length} font families:`, familyNames);
    
    // Map font family names to simplified names
    const fontNameMap = {
      'Libertinus Sans': 'sans',
      'Libertinus Serif': 'serif', 
      'TheSansMonoCond': 'mono'
    };
    
    // Filter and map to simplified names
    const simplifiedFonts = [];
    familyNames.forEach(name => {
      if (fontNameMap[name]) {
        simplifiedFonts.push({
          name: fontNameMap[name],
          value: name // Keep original name as value for internal use
        });
      }
    });
    
    // If no mapped fonts found, return all fonts as fallback
    if (simplifiedFonts.length === 0) {
      return familyNames.map(name => ({
        name: name,
        value: name
      }));
    }
    
    return simplifiedFonts;
  };

  const getTypefaceFromCache = (familyName, weight = 400, style = 'normal') => {
    const typefaceCache = typefaceCacheRef.current;
    const fontFamilyMap = fontFamilyMapRef.current;
    
    // Try exact match first
    const exactKey = `${familyName}-${weight}-${style}`;
    if (typefaceCache.has(exactKey)) {
      return typefaceCache.get(exactKey);
    }
    
    // Try fallbacks with different weights for the same style
    const fallbackWeights = [400, 500, 600, 300, 700, 200, 800, 100, 900];
    for (const fallbackWeight of fallbackWeights) {
      if (fallbackWeight === weight) continue;
      const fallbackKey = `${familyName}-${fallbackWeight}-${style}`;
      if (typefaceCache.has(fallbackKey)) {
        return typefaceCache.get(fallbackKey);
      }
    }
    
    // Try normal style with same weight
    if (style !== 'normal') {
      const normalKey = `${familyName}-${weight}-normal`;
      if (typefaceCache.has(normalKey)) {
        return typefaceCache.get(normalKey);
      }
    }
    
    // Final fallback: use any typeface from the family
    if (fontFamilyMap.has(familyName)) {
      return fontFamilyMap.get(familyName);
    }
    
    return null;
  };

  const getAvailableWeightsForFamily = (familyName) => {
    const typefaceCache = typefaceCacheRef.current;
    const weights = new Set();
    
    typefaceCache.forEach((typeface, key) => {
      if (key.startsWith(`${familyName}-`)) {
        const parts = key.split('-');
        if (parts.length >= 2) {
          const weight = parseInt(parts[1]);
          if (!isNaN(weight)) {
            weights.add(weight);
          }
        }
      }
    });
    
    return Array.from(weights).sort((a, b) => a - b);
  };

  const createSurface = (canvas) => {
    if (!canvasKitInstance || !canvas) return null;
    
    const surface = canvasKitInstance.MakeWebGLCanvasSurface(canvas);
    surfaceRef.current = surface;
    return surface;
  };

  useEffect(() => {
    const initializeCanvasKit = async () => {
      try {
        const ck = await initCanvasKit();
        if (ck) {
          setCanvasKitStatus('ready');
          setFontManager(await initFontMgr(ck));
        } else {
          console.error('❌ CanvasKit failed to load - application requires CanvasKit');
          setCanvasKitStatus('failed');
        }
      } catch (error) {
        console.error('💥 Error during initialization:', error);
        setCanvasKitStatus('failed');
      }
    };
    
    initializeCanvasKit();
    
    // Add a timeout to prevent hanging
    const timeoutId = setTimeout(() => {
      if (canvasKitStatus === 'loading' || !fontsLoaded) {
        console.warn('⏰ Initialization timeout, forcing app to show');
        setCanvasKitStatus('ready');
        setFontsLoaded(true);
      }
    }, 15000); // 15 second timeout
    
    return () => {
      clearTimeout(timeoutId);
    };
  }, []);

  const value = {
    // Status
    canvasKitStatus,
    fontsLoaded,
    
    // CanvasKit instances
    CanvasKit,
    canvasKitInstance,
    
    // Font data
    availableFonts,
    fontManager,
    
    // Surface management
    surfaceRef,
    createSurface,
    
    // Font utilities
    getTypefaceFromCache,
    getAvailableWeightsForFamily,
    
    // Refs for advanced usage
    typefaceCacheRef,
    fontFamilyMapRef,
  };

  return (
    <CanvasKitContext.Provider value={value}>
      {children}
    </CanvasKitContext.Provider>
  );
};
